package cn.bugstack.mybatis.session;

import cn.bugstack.mybatis.bindings.MapperRegistry;
import cn.bugstack.mybatis.datasource.druid.DruidDatasourceFactory;
import cn.bugstack.mybatis.datasource.pooled.PooledDataSourceFactory;
import cn.bugstack.mybatis.datasource.unpooled.UnpooledDataSourceFactory;
import cn.bugstack.mybatis.executor.Executor;
import cn.bugstack.mybatis.executor.ParameterHandler;
import cn.bugstack.mybatis.executor.SimpleExecutor;
import cn.bugstack.mybatis.executor.resultset.DefaultResultSetHandler;
import cn.bugstack.mybatis.executor.resultset.ResultSetHandler;
import cn.bugstack.mybatis.executor.statement.PreparedStatementHandler;
import cn.bugstack.mybatis.executor.statement.StatementHandler;
import cn.bugstack.mybatis.mapping.BoundSql;
import cn.bugstack.mybatis.mapping.Environment;
import cn.bugstack.mybatis.mapping.MappedStatement;
import cn.bugstack.mybatis.reflection.MetaObject;
import cn.bugstack.mybatis.reflection.factory.DefaultObjectFactory;
import cn.bugstack.mybatis.reflection.factory.ObjectFactory;
import cn.bugstack.mybatis.reflection.wrapper.DefaultObjectWrapperFactory;
import cn.bugstack.mybatis.reflection.wrapper.ObjectWrapperFactory;
import cn.bugstack.mybatis.scripting.LanguageDriverRegistry;
import cn.bugstack.mybatis.scripting.defaults.DefaultParameterHandler;
import cn.bugstack.mybatis.scripting.xmltags.XMLLanguageDriver;
import cn.bugstack.mybatis.session.defaults.DefaultSqlSession;
import cn.bugstack.mybatis.transaction.Transaction;
import cn.bugstack.mybatis.transaction.jdbc.JdbcTransactionFactory;
import cn.bugstack.mybatis.type.TypeAliasRegistry;
import cn.bugstack.mybatis.type.TypeHandlerRegistry;

import java.util.HashMap;
import java.util.Map;

public class Configuration {

    private Environment environment;


    private TypeAliasRegistry typeAliasRegistry = new TypeAliasRegistry();

    /**
     * store MappedStatement parsed from xmlConfigBuilder
     */
    private final Map<String, MappedStatement> mappedStatements = new HashMap<>();

    /**
     * MapperRegistry 和 Configuration 互相引用
     */
    private MapperRegistry mapperRegistry = new MapperRegistry(this);


    // 对象工厂和对象包装器工厂
    protected ObjectFactory objectFactory = new DefaultObjectFactory();
    protected ObjectWrapperFactory objectWrapperFactory = new DefaultObjectWrapperFactory();


    protected final LanguageDriverRegistry languageRegistry = new LanguageDriverRegistry();



    // 类型处理器注册机
    protected final TypeHandlerRegistry typeHandlerRegistry = new TypeHandlerRegistry();

    public TypeHandlerRegistry getTypeHandlerRegistry() {
        return typeHandlerRegistry;
    }

    public LanguageDriverRegistry getLanguageRegistry() {
        return languageRegistry;
    }




    public TypeAliasRegistry getTypeAliasRegistry() {
        return typeAliasRegistry;
    }

    public ObjectFactory getObjectFactory() {
        return objectFactory;
    }

    public Configuration() {
        typeAliasRegistry.registerAlias("JDBC", JdbcTransactionFactory.class);
        typeAliasRegistry.registerAlias("DRUID", DruidDatasourceFactory.class);
        typeAliasRegistry.registerAlias("POOLED", PooledDataSourceFactory.class);
        typeAliasRegistry.registerAlias("UNPOOLED", UnpooledDataSourceFactory.class);
        languageRegistry.setDefaultDriverClass(XMLLanguageDriver.class);
    }

    public void addMappedStatement(MappedStatement mappedStatement) {
        mappedStatements.put(mappedStatement.getId(), mappedStatement);
    }

    public MappedStatement getMappedStatement(MappedStatement mappedStatement) {
        return mappedStatements.get(mappedStatement.getId());
    }

    public void addMapper(Class<?> mapperInterface) {
        mapperRegistry.addMapper(mapperInterface);
    }

    public <T> T getMapper(Class<T> type, DefaultSqlSession defaultSqlSession) {
        return mapperRegistry.getMapper(type, defaultSqlSession);
    }


    public MappedStatement getMappedStatement(String statementName) {
        return mappedStatements.get(statementName);
    }


    public Environment getEnvironment() {
        return environment;
    }

    public void setEnvironment(Environment environment) {
        this.environment = environment;
    }



    public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
        return new PreparedStatementHandler(executor, mappedStatement, parameter, rowBounds, resultHandler, boundSql);
    }

    /**
     * 创建结果集处理器
     */
    public ResultSetHandler newResultSetHandler(Executor executor, MappedStatement mappedStatement, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
        return new DefaultResultSetHandler( mappedStatement,boundSql, resultHandler, objectFactory,rowBounds);
    }

    public Executor newExecutor(Transaction transaction) {
        return new SimpleExecutor(this, transaction, false);
    }


    public MetaObject newMetaObject(Object object) {
        return MetaObject.forObject(object, objectFactory, objectWrapperFactory);
    }

    public ParameterHandler newParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql) {
        return new DefaultParameterHandler(mappedStatement, parameterObject, boundSql);
    }
}
